package com.uatair.common.service;

import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;
import com.uatair.common.core.redis.RedisCache;
import com.uatair.common.kafka.domain.protobuf.FlightProto;
import com.uatair.common.mqtt.domain.task.SortieTask;
import com.uatair.common.mqtt.uploader.HeNanTaskUploader;
import com.uatair.common.mqtt.util.AESUtil;
import com.uatair.common.mqtt.util.UAesUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@RequiredArgsConstructor
public class FlightDetailService {

    @Autowired
    private RedisCache redisCache;

    /**
     * 根据架次号动态生成Protobuf二进制流
     */
    public FlightProto.FlightRecordDetail generateDetailBytes(SortieTask sortieTask) {
        List<String> strings = UAesUtil.downloadAndParseFile(sortieTask.getPath());
        if (!strings.isEmpty()) {
            List<JSONObject> traceJson = AESUtil.getJsonObjects(strings);
            List<FlightProto.FlightData> flightDataList = new ArrayList<>();
            long startMillis = sortieTask.getStartTime().toInstant().toEpochMilli();
            long endMillis = sortieTask.getEndTime().toInstant().toEpochMilli();
            long totalMillis = endMillis - startMillis;
            double intervalMillis = (double) totalMillis / ((traceJson.size()==1?2:traceJson.size()) - 1);
            int optMode = Integer.parseInt(sortieTask.getOptMode());
            for (int i = 0; i < traceJson.size(); i++) {
                JSONObject osd = traceJson.get(i);
                int sprayType = 0;
                if (osd.has("workArea")) {
                    double workArea = Double.parseDouble(osd.get("workArea").toString());
                    sprayType = workArea > 1 ? workArea < sortieTask.getSize() ? 1 : 0 : 0;
                } else {
                    double alt = Double.parseDouble(osd.get("relativeAlt").toString());
                    if (alt > 3)
                        sprayType = 1;
                }
                long currentMillis;
                if (i == traceJson.size() - 1) {
                    // 最后一个点直接使用结束时间，避免浮点误差
                    currentMillis = endMillis;
                } else {
                    // 使用四舍五入来减少累积误差
                    currentMillis = startMillis + Math.round(i * intervalMillis);
                }
                FlightProto.SprayInfo sprayInfo;
                FlightProto.SowInfo sowInfo;
                if (optMode==0){
                    sprayInfo = FlightProto.SprayInfo.newBuilder()
                            .setSprayType(sprayType)
                            .setFlowSpeed(sortieTask.getPumpSpeed().intValue())
                            .build();
                    sowInfo = FlightProto.SowInfo.newBuilder()
                            .setSowType(0)
                            .build();

                } else {
                    sprayInfo = FlightProto.SprayInfo.newBuilder()
                            .setSprayType(0)
                            .build();
                    sowInfo = FlightProto.SowInfo.newBuilder()
                            .setSowType(sprayType)
                            .setSowSpeed(sortieTask.getPumpSpeed().intValue())
                            .build();

                }
                FlightProto.FlightData flightData = FlightProto.FlightData.newBuilder()
                        .setCollectTime(currentMillis)
                        .setPosition(FlightProto.Position.newBuilder()
                                .setLatitude(Double.parseDouble(osd.get("lat").toString()))
                                .setLongitude(Double.parseDouble(osd.get("lon").toString()))
                                .build())
                        .setVelocity(FlightProto.Velocity.newBuilder()
                                .setX(Float.parseFloat(osd.get("vx").toString()))
                                .setY(Float.parseFloat(osd.get("vy").toString()))
                                .setZ(Float.parseFloat(osd.get("vz").toString()))
                                .build())
                        .setHeight(Float.parseFloat(osd.get("alt").toString()))
                        .setWorkMode("5".equals(sortieTask.getRouteMode()) ? 1 : 4)
                        .setSprayWidth(Float.parseFloat(sortieTask.getLineSpacing()==null?"0":sortieTask.getLineSpacing().toString()))
                        .setSprayInfo(sprayInfo)
                        .setSowInfo(sowInfo)
                        .build();
                flightDataList.add(flightData);
            }
            if (!flightDataList.isEmpty()) {
                FlightProto.FlightRecordDetail flightRecordDetail = FlightProto.FlightRecordDetail.newBuilder()
                        .setCount(flightDataList.size())
                        .setUsageType(optMode) // 0:喷洒 1:播撒
                        .addAllData(flightDataList)
                        .build();
                try {
                    //存入redis
                    Map<String, String> redisFlightRecord = new HashMap<>();
                    String jsonData = JsonFormat.printer().print(flightRecordDetail);
                    redisFlightRecord.put("flightData", jsonData);
                    String key = HeNanTaskUploader.HENAN_DOWNLOAD + sortieTask.getSortieNo();
                    redisCache.setCacheMap(key, redisFlightRecord);
                    redisCache.expire(key, HeNanTaskUploader.FLIGHT_TTL_DAYS, TimeUnit.DAYS);
                } catch (InvalidProtocolBufferException e) {
                    throw new RuntimeException(e);
                }
                return flightRecordDetail;
            }
        }
        return null;
    }
}
